package com.cgycms.webdeploy.ftp;

import cn.hutool.core.util.StrUtil;
import com.jcraft.jsch.*;
import lombok.Data;
import lombok.ToString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

/**
 * @ClassName : FtpUtil
 * @Description : 服务器ftp工具类
 * @Author : 王力超
 * @Date: 2020-10-14 18:33
 */
@Data
@ToString
public class FtpUtil {

    private static Logger log = LoggerFactory.getLogger(FtpUtil.class);

    private ChannelSftp sftp = null;

    /**
     * 分组
     */
    private String group;
    /**
     * 标签
     */
    private String title;
    /**
     * 账号
     */
    private String user;
    /**
     * ip
     */
    private String host;
    /**
     * 密码
     */
    private String password;
    /**
     * 端口
     */
    private int port = 22;
    /**
     * 上传地址
     */
    private String directory = "";
    /**
     * 下载目录
     */
    private String saveFile = "";

    public FtpUtil(String host, int port, String username, String password, String directory, String saveFile, String group, String title) {
        this.host = host;
        this.port = port;
        this.user = username;
        this.password = password;
        this.directory = directory;
        this.saveFile = saveFile;
        this.group = group;
        this.title = title;
    }

    public FtpUtil() {

    }

    /**
     * 创建连接
     *
     * @return
     */
    public FtpUtil createConnect() {
        log.info("[{}]开始连接服务器操作！", this.host);
        try {
            JSch jsch = new JSch();
            Session sshSession = jsch.getSession(user, host, port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            Class cl = ChannelSftp.class;
            Field f = cl.getDeclaredField("server_version");
            f.setAccessible(true);
            f.set(channel, 2);
            sftp = (ChannelSftp) channel;
            sftp.setFilenameEncoding("utf-8");
            log.info("[{}]连接服务器成功！", this.host);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("[{}]连接服务器失败！", this.host);
        }
        return this;
    }

    /**
     * @param uploadFile 上传文件的路径
     * @return 服务器上文件名
     */
    public boolean upload(InputStream uploadFile, String fileName, int retry, String serverPath) {
        try {
            sftp.cd(serverPath);
            sftp.put(uploadFile, fileName);
            log.info("[{}][{}]上传完成！", this.host, fileName);
            return true;
        } catch (Exception e) {
            if (0 < retry) {
                String key = "no such file";
                if (e.getMessage() != null && key.equals(e.getMessage().toLowerCase())) {
                    createDir(serverPath);
                    log.warn("不存在当前目录,自动创建[{}][{}]", this.host, serverPath);
                }
                return upload(uploadFile, fileName, retry - 1, serverPath);
            }
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 默认路径上传
     *
     * @param uploadFile 文件路径
     * @param fileName   文件名称
     * @param retry      重试次数
     * @return
     */
    public boolean upload(String uploadFile, String fileName, int retry) {
        try {
            return upload(new FileInputStream(uploadFile), fileName, retry, directory);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 下载文件
     */
    public void download(String path, String downloadFileName, String tmp) {
        FileOutputStream outputStream = null;
        try {
            log.info("[{}][{}]开始执行下载操作！", this.host, downloadFileName);
            File file = new File(tmp + "/" + downloadFileName);
            outputStream = new FileOutputStream(file);
            sftp.get(path + downloadFileName, outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != outputStream) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 删除文件
     */
    public boolean delete(String path, String fileName) {
        try {
            sftp.cd(path);
            sftp.rm(fileName);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 列出目录下的文件
     *
     * @throws SftpException
     */
    private Vector<ChannelSftp.LsEntry> listFiles(String directory)
            throws SftpException {
        return sftp.ls(directory);
    }

    /**
     * 列出目录下的文件,返回list
     *
     * @throws SftpException
     */
    public List listFilesToList(String directory) {
        List<String> result = new ArrayList<>();
        try {
            Vector<ChannelSftp.LsEntry> vector = listFiles(directory);
            for (ChannelSftp.LsEntry lsEntry : vector) {
                String filename = lsEntry.getFilename();
                if (".".equals(filename) || "..".equals(filename)) {
                    continue;
                }
                result.add(filename);
            }
        } catch (SftpException e) {
            e.printStackTrace();
            log.info("[{}][{}]获取目录下文件失败！", this.host, directory);
        }
        return result;
    }

    /**
     * 创建目录
     */
    public void createDir(String directory) {
        try {
            if (isDirExist(directory)) {
                this.sftp.cd(directory);
                return;
            }
            String[] pathArray = directory.split("/");
            StringBuffer filePath = new StringBuffer("/");
            for (String path : pathArray) {
                if (StrUtil.isBlank(path)) {
                    continue;
                }
                filePath.append(path + "/");
                if (isDirExist(filePath.toString())) {
                    sftp.cd(filePath.toString());
                } else {
                    // 建立目录
                    sftp.mkdir(filePath.toString());
                    // 进入并设置为当前目录
                    sftp.cd(filePath.toString());
                }
            }
            this.sftp.cd(directory);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断目录是否存在
     */
    public boolean isDirExist(String directory) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS lstat = sftp.lstat(directory);
            isDirExistFlag = true;
            return lstat.isDir();
        } catch (Exception e) {
            String key = "no such file";
            if (key.equals(e.getMessage().toLowerCase())) {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }

    /**
     * 关闭连接
     */
    public void quit() {
        sftp.quit();
        sftp.disconnect();
    }

}
